home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / gfxutil.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  10KB  |  454 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Common code needed by all the various graphics systems.
  5.   *
  6.   * (c) 1996 Bernd Schmidt, Ed Hanway, Samuel Devulder
  7.   */
  8.  
  9. #include "sysconfig.h"
  10. #include "sysdeps.h"
  11.  
  12. #include "config.h"
  13. #include "options.h"
  14. #include "threaddep/penguin.h"
  15. #include "memory.h"
  16. #include "custom.h"
  17. #include "keyboard.h"
  18. #include "xwin.h"
  19. #include "keybuf.h"
  20.  
  21. #define    RED     0
  22. #define    GRN    1
  23. #define    BLU    2
  24.  
  25. /*
  26.  * dither matrix
  27.  */
  28. static uae_u8 dither[4][4] =
  29. {
  30.   {0,8,2,10},
  31.   {12,4,14,6},
  32.   {3,11,1,9},
  33.   {14 /* 15 */,7,13,5}
  34. };
  35.  
  36. unsigned long doMask(int p, int bits, int shift)
  37. {
  38.     /* p is a value from 0 to 15 (Amiga color value)
  39.      * scale to 0..255, shift to align msb with mask, and apply mask */
  40.  
  41.     unsigned long val = p * 0x11111111UL;
  42.     val >>= (32 - bits);
  43.     val <<= shift;
  44.  
  45.     return val;
  46. }
  47.  
  48. void alloc_colors64k(int rw, int gw, int bw, int rs, int gs, int bs)
  49. {
  50.     int i;
  51.     for(i=0; i<4096; i++) {
  52.     int r = i >> 8;
  53.     int g = (i >> 4) & 0xF;
  54.     int b = i & 0xF;
  55.     xcolors[i] = doMask(r, rw, rs) | doMask(g, gw, gs) | doMask(b, bw, bs);
  56.     }
  57. }
  58.  
  59. static int allocated[4096];
  60. static int color_diff[4096];
  61. static int newmaxcol = 0;
  62.  
  63. void setup_maxcol(int max)
  64. {
  65.     newmaxcol = max;
  66. }
  67.  
  68. void alloc_colors256(allocfunc_type allocfunc)
  69. {
  70.     int nb_cols[3]; /* r,g,b */
  71.     int maxcol = newmaxcol == 0 ? 256 : newmaxcol;
  72.     int i,j,k,l,t;
  73.  
  74.     xcolnr *map;
  75.  
  76.     map = (xcolnr *)malloc(sizeof(xcolnr) * maxcol);
  77.     if(!map) {
  78.     write_log("Not enough mem for colormap!\n");
  79.     abort();
  80.     }
  81.  
  82.     /*
  83.      * compute #cols per components
  84.      */
  85.     for(i = 1; i*i*i <= maxcol; ++i)
  86.     ;
  87.     --i;
  88.  
  89.     nb_cols[RED] = i;
  90.     nb_cols[GRN] = i;
  91.     nb_cols[BLU] = i;
  92.  
  93.     /*
  94.      * set the colormap
  95.      */
  96.     l=0;
  97.     for(i = 0; i < nb_cols[RED]; ++i) {
  98.     int r = (i * 15) / (nb_cols[RED] - 1);
  99.     for(j = 0; j < nb_cols[GRN]; ++j) {
  100.         int g = (j * 15) / (nb_cols[GRN] - 1);
  101.         for(k = 0; k < nb_cols[BLU]; ++k) {
  102.         int b = (k * 15) / (nb_cols[BLU] - 1);
  103.         int result;
  104.         result = allocfunc(r, g, b, map + l);
  105.              if(!result) {free(map);return;}/* sam:speedup for amiga port */
  106.         l++;
  107.         }
  108.     }
  109.     }
  110. /*    printf("%d color(s) lost\n",maxcol - l);*/
  111.  
  112.     /*
  113.      * for each component compute the mapping
  114.      */
  115.     {
  116.     int diffr, diffg, diffb, maxdiff = 0, won = 0, lost;
  117.     int r, d = 8;
  118.     for(r=0; r<16; ++r) {
  119.         int cr, g, q;
  120.  
  121.         k  = nb_cols[RED]-1;
  122.         cr = (r * k) / 15;
  123.         q  = (r * k) % 15;
  124.         if(q > d && cr < k) ++cr;
  125.         diffr = abs(cr*k-r);
  126.         for(g=0; g<16; ++g) {
  127.         int cg, b;
  128.  
  129.         k  = nb_cols[GRN]-1;
  130.         cg = (g * k) / 15;
  131.         q  = (g * k) % 15;
  132.         if(q > d && cg < k) ++cg;
  133.         diffg = abs(cg*k-g);
  134.         for(b=0; b<16; ++b) {
  135.             int cb, rgb = (r<<8) | (g<<4) | b;
  136.  
  137.             k  = nb_cols[BLU]-1;
  138.             cb = (b * k) / 15;
  139.             q  = (b * k) % 15;
  140.             if(q > d && cb < k) ++cb;
  141.             diffb = abs(cb*k-b);
  142.             xcolors[rgb] = map[(cr*nb_cols[GRN]+cg)*nb_cols[BLU]+cb];
  143.             color_diff[rgb] = diffr+diffg+diffb;
  144.             if (color_diff[rgb] > maxdiff)
  145.             maxdiff = color_diff[rgb];
  146.         }
  147.         }
  148.     }
  149.     while (maxdiff > 0 && l < maxcol) {
  150.         int newmaxdiff = 0;
  151.         lost = 0; won++;
  152.         for(r = 15; r >= 0; r--) {
  153.         int cr, g, q;
  154.  
  155.         for(g = 15; g >= 0; g--) {
  156.             int cg, b;
  157.  
  158.             for(b = 15; b >= 0; b--) {
  159.             int cb, rgb = (r<<8) | (g<<4) | b;
  160.  
  161.             if (color_diff[rgb] == maxdiff) {
  162.                 int result;
  163.  
  164.                 if (l >= maxcol)
  165.                 lost++;
  166.                 else {
  167.                 result = allocfunc(r, g, b, xcolors + rgb);
  168.                 if(!result) {free(map);return;} /* sam */
  169.                 l++;
  170.                 }
  171.                 color_diff[rgb] = 0;
  172.             } else if (color_diff[rgb] > newmaxdiff)
  173.                 newmaxdiff = color_diff[rgb];
  174.  
  175.             }
  176.         }
  177.         }
  178.         maxdiff = newmaxdiff;
  179.     }
  180. /*    printf("%d color(s) lost, %d stages won\n",lost, won);*/
  181.     }
  182.     free (map);
  183. }
  184.  
  185. /*
  186.  * This dithering process works by letting UAE run internaly in 12bit
  187.  * mode and doing the dithering on the fly when rendering to the display.
  188.  * The dithering algorithm is quite fast but uses lot of memory (4*8*2^12 =
  189.  * 128Kb). I don't think that is a trouble right now, but when UAE will
  190.  * emulate AGA and work internaly in 24bit mode, that dithering algorithm
  191.  * will need 4*8*2^24 = 512Mb. Obviously that fast algorithm will not be
  192.  * tractable. However, we could then use an other algorithm, slower, but
  193.  * far more reasonable (I am thinking about the one that is used in DJPEG).
  194.  */
  195.  
  196. uae_u8 cidx[4][8*4096]; /* fast, but memory hungry =:-( */
  197.  
  198. /*
  199.  * Compute dithering structures
  200.  */
  201. void setup_greydither_maxcol(int maxcol, allocfunc_type allocfunc)
  202. {
  203.     int i,j,k,l,t;
  204.     xcolnr *map;
  205.  
  206.     for (i = 0; i < 4096; i++)
  207.     xcolors[i] = i;
  208.  
  209.     map = (xcolnr *)malloc(sizeof(xcolnr) * maxcol);
  210.     if(!map) {
  211.     write_log("Not enough mem for colormap!\n");
  212.     abort();
  213.     }
  214.  
  215.     /*
  216.      * set the colormap
  217.      */
  218.     for(i = 0; i < maxcol; ++i) {
  219.     int c, result;
  220.     c = (15 * i + (maxcol-1)/2) / (maxcol - 1);
  221.     result = allocfunc(c, c, c, map + i);
  222.     /* @@@ check for errors */
  223.     if(!result) {free(map);return;} /* sam */
  224.     }
  225.  
  226.     /*
  227.      * for each componant compute the mapping
  228.      */
  229.     for(i=0;i<4;++i) {
  230.     for(j=0;j<4;++j) {
  231.         int r, d = dither[i][j]*17;
  232.         for(r=0; r<16; ++r) {
  233.         int g;
  234.         for(g=0; g<16; ++g) {
  235.             int  b;
  236.             for(b=0; b<16; ++b) {
  237.             int rgb = (r<<8) | (g<<4) | b;
  238.             int c,p,q;
  239.  
  240.             c = (77  * r +
  241.                  151 * g +
  242.                  28  * b) / 15; /* c in 0..256 */
  243.  
  244.             k = maxcol-1;
  245.             p = (c * k) / 256;
  246.             q = (c * k) % 256;
  247.             if(q /*/ k*/> d /*/ k*/ && p < k) ++p;
  248. /* sam:                      ^^^^^^^ */
  249. /*  It seems that produces better output */
  250.             cidx[i][rgb + (j+4)*4096] =
  251.                 cidx[i][rgb + j*4096] = map[p];
  252.             }
  253.         }
  254.         }
  255.     }
  256.     }
  257.     free (map);
  258. }
  259.  
  260. void setup_greydither(int bits, allocfunc_type allocfunc)
  261. {
  262.     setup_greydither_maxcol(1 << bits, allocfunc);
  263. }
  264.  
  265. void setup_dither(int bits, allocfunc_type allocfunc)
  266. {
  267.     int nb_cols[3]; /* r,g,b */
  268.     int maxcol = 1 << bits;
  269.     int i,j,k,l,t;
  270.  
  271.     xcolnr *map;
  272.     int *redvals, *grnvals, *bluvals;
  273.  
  274.     map = (xcolnr *)malloc(sizeof(xcolnr) * maxcol);
  275.     if(!map) {
  276.     write_log("Not enough mem for colormap!\n");
  277.     abort();
  278.     }
  279.  
  280.     for (i = 0; i < 4096; i++)
  281.     xcolors[i] = i;
  282.  
  283.     /*
  284.      * compute #cols per components
  285.      */
  286.     for(i = 1; i*i*i <= maxcol; ++i)
  287.     ;
  288.     --i;
  289.  
  290.     nb_cols[RED] = i;
  291.     nb_cols[GRN] = i;
  292.     nb_cols[BLU] = i;
  293.  
  294.     if(nb_cols[RED]*(++i)*nb_cols[BLU] <= maxcol) {
  295.     nb_cols[GRN] = i;
  296.     if((i)*nb_cols[GRN]*nb_cols[BLU] <= maxcol) nb_cols[RED] = i;
  297.     }
  298.  
  299.     redvals = (int *)malloc(sizeof(int) * maxcol);
  300.     grnvals = redvals + nb_cols[RED];
  301.     bluvals = grnvals + nb_cols[GRN];
  302.     /*
  303.      * set the colormap
  304.      */
  305.     l=0;
  306.     for(i = 0; i < nb_cols[RED]; ++i) {
  307.     int r = (i * 15) / (nb_cols[RED] - 1);
  308.     redvals[i] = r;
  309.     for(j = 0; j < nb_cols[GRN]; ++j) {
  310.         int g = (j * 15) / (nb_cols[GRN] - 1);
  311.         grnvals[j] = g;
  312.         for(k = 0; k < nb_cols[BLU]; ++k) {
  313.         int b = (k * 15) / (nb_cols[BLU] - 1);
  314.         int result;
  315.         bluvals[k] = b;
  316.         result = allocfunc(r, g, b, map + l);
  317.         if(!result) {free(map);free(redvals);return;} /* sam */
  318.         l++;
  319.         }
  320.     }
  321.     }
  322. /*    fprintf(stderr, "%d color(s) lost\n",maxcol - l);*/
  323.  
  324.     /*
  325.      * for each component compute the mapping
  326.      */
  327.     {
  328.     int r;
  329.     for(r=0; r<16; ++r) {
  330.         int g;
  331.         for(g=0; g<16; ++g) {
  332.         int b;
  333.         for(b=0; b<16; ++b) {
  334.             int rederr = 0, grnerr = 0, bluerr = 0;
  335.             int rgb = (r<<8) | (g<<4) | b;
  336.  
  337.             for(i=0;i<4;++i) for(j=0;j<4;++j) {
  338.             int d = dither[i][j];
  339.             int cr, cg, cb, k, q;
  340. #if 0 /* Slightly different algorithm. Needs some tuning. */
  341.             k  = nb_cols[RED]-1;
  342.             cr = r * k / 15;
  343.             q  = r * k - 15*cr;
  344.             if (cr < 0) cr = 0;
  345.             else
  346.                 if(q / k > d / k && rederr <= 0) ++cr;
  347.             if (cr > k) cr = k;
  348.             rederr += redvals[cr]-r;
  349.  
  350.             k  = nb_cols[GRN]-1;
  351.             cg = g * k / 15;
  352.             q  = g * k - 15*cg;
  353.             if (cg < 0) cg = 0;
  354.             else
  355.                 if (q / k > d / k && grnerr <= 0) ++cg;
  356.             if (cg > k) cg = k;
  357.             grnerr += grnvals[cg]-g;
  358.  
  359.             k  = nb_cols[BLU]-1;
  360.             cb = b * k / 15;
  361.             q  = b * k - 15*cb;
  362.             if (cb < 0) cb = 0;
  363.             else
  364.                 if (q / k > d / k && bluerr <= 0) ++cb;
  365.             if (cb > k) cb = k;
  366.             bluerr += bluvals[cb]-b;
  367. #else
  368.             k  = nb_cols[RED]-1;
  369.             cr = r * k / 15;
  370.             q  = r * k - 15*cr;
  371.             if (cr < 0) cr = 0;
  372.             else
  373.                 if(q /*/ k*/ > d /*/ k*/) ++cr;
  374.             if (cr > k) cr = k;
  375.  
  376.             k  = nb_cols[GRN]-1;
  377.             cg = g * k / 15;
  378.             q  = g * k - 15*cg;
  379.             if (cg < 0) cg = 0;
  380.             else
  381.                 if (q /*/ k*/ > d /*/ k*/) ++cg;
  382.             if (cg > k) cg = k;
  383.  
  384.             k  = nb_cols[BLU]-1;
  385.             cb = b * k / 15;
  386.             q  = b * k - 15*cb;
  387.             if (cb < 0) cb = 0;
  388.             else
  389.                 if (q /*/ k*/ > d /*/ k*/) ++cb;
  390.             if (cb > k) cb = k;
  391. #endif
  392.             cidx[i][rgb + (j+4)*4096] = cidx[i][rgb + j*4096] = map[(cr*nb_cols[GRN]+cg)*nb_cols[BLU]+cb];
  393.             }
  394.         }
  395.         }
  396.     }
  397.     }
  398.     free (map);
  399. }
  400.  
  401. #if !defined X86_ASSEMBLY
  402. /*
  403.  * Dither the line.
  404.  * Make sure you call this only with (len & 3) == 0, or you'll just make
  405.  * yourself unhappy.
  406.  */
  407.  
  408. void DitherLine(uae_u8 *l, uae_u16 *r4g4b4, int x, int y, uae_s16 len, int bits)
  409. {
  410.     uae_u8 *dith = cidx[y&3]+(x&3)*4096;
  411.     uae_u8 d = 0;
  412.     int bitsleft = 8;
  413.  
  414.     if(bits == 8) {
  415.     while(len>0) {
  416.         *l++ = dith[0*4096 + *r4g4b4++];
  417.         *l++ = dith[1*4096 + *r4g4b4++];
  418.         *l++ = dith[2*4096 + *r4g4b4++];
  419.         *l++ = dith[3*4096 + *r4g4b4++];
  420.         len -= 4;
  421.     }
  422.     return;
  423.     }
  424.  
  425.     while(len) {
  426.     int v;
  427.     v = dith[0*4096 + *r4g4b4++];
  428.     bitsleft -= bits;
  429.     d |= (v << bitsleft);
  430.     if (!bitsleft)
  431.         *l++ = d, bitsleft = 8, d = 0;
  432.  
  433.     v = dith[1*4096 + *r4g4b4++];
  434.     bitsleft -= bits;
  435.     d |= (v << bitsleft);
  436.     if (!bitsleft)
  437.         *l++ = d, bitsleft = 8, d = 0;
  438.  
  439.     v = dith[2*4096 + *r4g4b4++];
  440.     bitsleft -= bits;
  441.     d |= (v << bitsleft);
  442.     if (!bitsleft)
  443.         *l++ = d, bitsleft = 8, d = 0;
  444.  
  445.     v = dith[3*4096 + *r4g4b4++];
  446.     bitsleft -= bits;
  447.     d |= (v << bitsleft);
  448.     if (!bitsleft)
  449.         *l++ = d, bitsleft = 8, d = 0;
  450.     len -= 4;
  451.     }
  452. }
  453. #endif
  454.